<?php
namespace app\utils;
use App;
/**
 *  getRealPath 获取真实路径
 *  getUrlPath	获取URL 路径
 * 	getCurrentPath 
 * 	getCurrentUrl
 *  checkPath 	检测输入的路径是否可用
 *  buildUrl 	生成URL路径
 * 	buildPath 	生成真实路径
 * 	can 		权限检查
 * */
class Path extends \app\BaseObject{
	const TYPE_ROOT = 'root';
	const TYPE_THUMB = 'thumb';

	const ROLE_CHECK_PATH = 'cp';
	const ROLE_WRITE= 'w';
	const ROLE_DELETE= 'd';
	private static $denyChars = "\<|\>|\\|'|\"|..|.";
	private static $denyPath = ['root', 'var', 'etc'];
	private static $keys = ['..', '/', '^', '&', '@', '!', '*', '(', ')', '%'];
	private $_data;
	public function init(){
		$root = rtrim(App::$app->getOption('current_path'), '/');
		$thumb = rtrim(App::$app->getOption('thumbs_base_path'), '/');
		$root_url = rtrim(App::$app->getOption('upload_dir'), '/');
		$thumb_url = rtrim(App::$app->getOption('thumbs_upload_dir'), '/');
		$this->_data['root'] = realpath($root);
		$this->_data['thumb'] = realpath($thumb);
		$this->_data['root_url'] = $root_url;
		$this->_data['thumb_url'] = $thumb_url;
	}
	

	/**
	 * 真實路徑  /$root/$path 不包含後綴 / 或ds
	 * */
	public function getRealPath($type='root'){
		switch ($type) {
			case self::TYPE_THUMB:
				return $this->_data['thumb'];
				break;			
			default:
				return $this->_data['root'];
				break;
		}
	}

	public function getUrlPath($type='root'){
		switch ($type) {
			case self::TYPE_THUMB:
				return $this->_data['thumb_url'];
				break;
			
			default:
				return $this->_data['root_url'];
				break;
		}
	}

	/**
	 * 返回包含ds的路徑
	 * */
	public function getCurrentPath($path, $type='root'){
		$path = $this->fixPath($path);
		$path = $this->getRealPath($type) . DIRECTORY_SEPARATOR . $this->buildPath($path);
		return $this->formatPath($path, DIRECTORY_SEPARATOR);
	}
	/**
	 * 返回URL 使用的路径
	 * */
	public function getCurrentUrl($path, $type='root'){
		$path = $this->fixPath($path);
		$path = $this->getUrlPath($type) . '/' . $this->buildPath($path);
		return $this->formatPath($path, '/');
	}
	
	public function buildPath($file, $path='', $ds = '/'){
		$path_arr = [];
		if(!empty($path)){
			$path_arr[] = $path;
		}
		if(!empty($file)){
			$path_arr[] = $file;
		}
		
		return empty($path_arr) ? '' : implode($ds, $path_arr);
	}
	/**
	 * 生成文件包含路徑
	 * */
	public function buildFilePath($file, $path='', $type='root'){
		$path = $this->getCurrentPath($path, true, $type);
		return $path . $file;
	}
	/**
	 * 生成文件url
	 * */
	public function buildFileUrl($file, $path='', $type='root'){
		switch ($type) {
			case self::TYPE_THUMB:
				$path = $this->formatPath($this->thumbPath . '/' . $this->buildPath($path), '/');
				return $path . $file;
				break;
			
			default:
				return $this->path . '/' . $this->buildPath($file, $path);
				break;
		}
	}
	/**
	 * 生成root真实路径
	 * */
	public function buildDir($new_path, $path){
		$new_path = $this->fixName($new_path);
		$new_path = $this->buildPath($new_path, $path, DIRECTORY_SEPARATOR);
		return $this->formatPath($this->getRealPath() . DIRECTORY_SEPARATOR . $new_path, DIRECTORY_SEPARATOR);
	}
	public function buildToArray($path, $root){
		$subdir = str_replace($root, '', $path);
		$subdir = !empty($subdir) ? explode(DIRECTORY_SEPARATOR, $subdir) : [];
		return $subdir;
	}

	public function can($role, $path){
		switch ($role) {
			case self::ROLE_CHECK_PATH:
				return self::isSafePath($path) && self::urlDecodeCheck($path);
			case 'wt':
				$root = $this->getRealPath('thumb');
				return $this->checkPath($path, $root);
				break;
			
			default:
				$root = $this->getRealPath();
				return $this->checkPath($path, $root);
				break;
		}
	}
	public function checkPath($path, $root){
		$path = $this->toAbsolute($path);
		$subdir = str_replace($root, '', $path);
		return strlen($root) <= strlen($path)
				&& strlen($subdir)!=strlen($path);
	}
	/**
	 * 相对路径转真实路径
	 * */
	public function toAbsolute($path){
		$path = str_replace('/', DIRECTORY_SEPARATOR, $path);
		$paths = explode(DIRECTORY_SEPARATOR, $path);
		$current_p = '';
		foreach ($paths as $key => $p) {
			if($p == '.'){
				continue;
			}else if($p == '..'){
				$current_p = dirname($current_p).DIRECTORY_SEPARATOR;
			}else{
				$current_p .= $p . DIRECTORY_SEPARATOR;
			}
		}
		return $current_p;
	}
	public static function isSafePath($path){
		if(empty($path)){
            return true;
        }        
        if(self::checkSpecialCharacters($path)){
        	return false;
        }
        foreach(self::$denyPath as $val){
        	if(strpos($path, $val)!==false){
        		return false;
        	}
        }
        return true;
	}
	public static function urlDecodeCheck(String $value){
        $value = urldecode($value);
        return self::isSafePath($value);
    }
    public static function checkSpecialCharacters(String $value){
        $pattern = "/[".self::$denyChars."]/";
        if(preg_match($pattern, $value)){
            return true;
        }
        $value2 = urldecode($value);
        if(preg_match($pattern, $value2)){
            return true;
        }
        $value2 = html_entity_decode($value, ENT_COMPAT, 'UTF-8');
        if(preg_match($pattern, $value2)){
            return true;
        }
        return false;
    }
	public function fixName($path){
		$path = str_replace(self::$keys, '_', $path);
		return $path;
	}
	public function fixPath($path, $ds = '/'){
		$path = !empty($path) ? ltrim($path, $ds) : '';
		$path = !empty($path) ? rtrim($path, $ds) : '';
		return $path;
	}
	public function getCurDir($path=''){
		return $this->getCurrentUrl($path);
		// $path = $this->fixPath($path);
		// return empty($path) ? '/' :  ($path . '/');
	}
	/*
	* 格式路徑 最后包含 ds
	*/
	public function formatPath($path, $ds = '/'){
		return rtrim($path, $ds) . $ds;
	}

}